# -*- coding: utf-8 -*-
"""
Allure测试配置

提供Allure测试报告的全局配置和fixture
"""

import os
import pytest
import allure
import json
import time
from datetime import datetime
from pathlib import Path
from typing import Dict, Any
from utils.allure_utils import AllureHelper, AllureReporter
from utils.logger import get_logger
from utils.config import get_config

# 配置日志
logger = get_logger(__name__)


@pytest.fixture(scope="session", autouse=True)
def setup_allure_environment():
    """
    设置Allure测试环境信息
    
    在测试会话开始时自动执行，设置环境信息
    """
    try:
        config = get_config()
        
        # 环境信息
        env_info = {
            "Test.Environment": config.get("environment", "test"),
            "API.Base.URL": config.get("api_base_url", "http://localhost:8000"),
            "Python.Version": f"{os.sys.version_info.major}.{os.sys.version_info.minor}.{os.sys.version_info.micro}",
            "Operating.System": "Windows" if os.name == "nt" else os.name,
            "Test.Framework": "pytest",
            "API.Framework": "FastAPI",
            "Test.Start.Time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "Test.Executor": os.environ.get("USER", os.environ.get("USERNAME", "Unknown")),
            "Build.Version": os.environ.get("BUILD_VERSION", "dev"),
            "Branch.Name": os.environ.get("GIT_BRANCH", "main")
        }
        
        # 添加环境信息到Allure
        AllureHelper.add_environment_info(env_info)
        
        # 执行器信息
        executor_info = {
            "name": "pytest",
            "type": "pytest",
            "url": config.get("ci_url", ""),
            "buildOrder": int(time.time()),
            "buildName": f"API-Test-{datetime.now().strftime('%Y%m%d-%H%M%S')}",
            "buildUrl": os.environ.get("BUILD_URL", ""),
            "reportName": "API自动化测试报告",
            "reportUrl": ""
        }
        
        # 添加执行器信息到Allure
        AllureHelper.add_executor_info(executor_info)
        
        logger.info("Allure环境信息设置完成")
        
    except Exception as e:
        logger.error(f"设置Allure环境信息失败: {e}")


@pytest.fixture(scope="session")
def allure_reporter():
    """
    Allure报告生成器fixture
    
    Returns:
        AllureReporter: 报告生成器实例
    """
    return AllureReporter()


@pytest.fixture(autouse=True)
def test_case_setup(request):
    """
    测试用例自动设置
    
    为每个测试用例自动添加基础信息
    """
    try:
        # 获取测试用例信息
        test_name = request.node.name
        test_module = request.node.module.__name__ if request.node.module else "Unknown"
        test_class = request.node.cls.__name__ if request.node.cls else "Unknown"
        
        # 添加测试用例标签
        allure.dynamic.tag("automated")
        allure.dynamic.tag(f"module:{test_module}")
        
        if test_class != "Unknown":
            allure.dynamic.tag(f"class:{test_class}")
        
        # 添加测试用例链接（如果有）
        if hasattr(request.node, 'get_closest_marker'):
            # 检查是否有issue标记
            issue_marker = request.node.get_closest_marker('issue')
            if issue_marker and issue_marker.args:
                issue_id = issue_marker.args[0]
                allure.dynamic.issue(issue_id)
            
            # 检查是否有testcase标记
            testcase_marker = request.node.get_closest_marker('testcase')
            if testcase_marker and testcase_marker.args:
                case_id = testcase_marker.args[0]
                allure.dynamic.testcase(case_id)
        
        # 记录测试开始时间
        start_time = time.time()
        request.node.start_time = start_time
        
        logger.debug(f"测试用例 {test_name} 开始执行")
        
    except Exception as e:
        logger.error(f"测试用例设置失败: {e}")


@pytest.fixture(autouse=True)
def test_case_teardown(request):
    """
    测试用例自动清理
    
    在测试用例结束后执行清理工作
    """
    yield  # 等待测试执行完成
    
    try:
        # 计算测试执行时间
        if hasattr(request.node, 'start_time'):
            execution_time = time.time() - request.node.start_time
            allure.attach(
                f"{execution_time:.3f}秒",
                name="执行时间",
                attachment_type=allure.attachment_type.TEXT
            )
        
        # 获取测试结果
        test_result = "PASSED"
        if hasattr(request.node, 'rep_call'):
            if request.node.rep_call.failed:
                test_result = "FAILED"
            elif request.node.rep_call.skipped:
                test_result = "SKIPPED"
        
        logger.debug(f"测试用例 {request.node.name} 执行完成，结果: {test_result}")
        
    except Exception as e:
        logger.error(f"测试用例清理失败: {e}")


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """
    pytest钩子：生成测试报告
    
    捕获测试执行结果并添加到节点中
    """
    outcome = yield
    rep = outcome.get_result()
    
    # 将报告添加到测试项中
    setattr(item, f"rep_{rep.when}", rep)
    
    # 如果测试失败，添加失败信息到Allure
    if rep.when == "call" and rep.failed:
        try:
            # 添加失败截图或日志
            if hasattr(rep, 'longrepr') and rep.longrepr:
                allure.attach(
                    str(rep.longrepr),
                    name="失败详情",
                    attachment_type=allure.attachment_type.TEXT
                )
            
            # 添加失败时的环境信息
            failure_info = {
                "测试名称": item.name,
                "失败时间": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "失败阶段": rep.when,
                "异常类型": rep.longrepr.reprcrash.message if hasattr(rep.longrepr, 'reprcrash') else "Unknown"
            }
            
            AllureHelper.attach_json(failure_info, "失败信息")
            
        except Exception as e:
            logger.error(f"添加失败信息到Allure失败: {e}")


@pytest.fixture
def allure_step():
    """
    Allure步骤fixture
    
    提供便捷的步骤创建方法
    """
    return AllureHelper.step


@pytest.fixture
def allure_attach():
    """
    Allure附件fixture
    
    提供便捷的附件添加方法
    """
    class AttachHelper:
        @staticmethod
        def text(content: str, name: str = "文本附件"):
            AllureHelper.attach_text(content, name)
        
        @staticmethod
        def json(data: Dict[str, Any], name: str = "JSON数据"):
            AllureHelper.attach_json(data, name)
        
        @staticmethod
        def file(file_path: str, name: str = None):
            AllureHelper.attach_file(file_path, name)
    
    return AttachHelper()


@pytest.fixture(scope="session")
def cleanup_old_results():
    """
    清理旧的测试结果
    
    在测试会话开始前清理旧的结果文件
    """
    try:
        # 清理7天前的结果
        AllureHelper.cleanup_old_results(days=7)
        logger.info("已清理旧的测试结果")
    except Exception as e:
        logger.error(f"清理旧结果失败: {e}")


# 自定义标记
pytest_plugins = []


def pytest_configure(config):
    """
    pytest配置钩子
    
    注册自定义标记
    """
    # 注册自定义标记
    config.addinivalue_line(
        "markers", "issue(issue_id): 标记测试用例关联的问题ID"
    )
    config.addinivalue_line(
        "markers", "testcase(case_id): 标记测试用例关联的用例ID"
    )
    config.addinivalue_line(
        "markers", "api: 标记API接口测试"
    )
    config.addinivalue_line(
        "markers", "performance: 标记性能测试"
    )
    config.addinivalue_line(
        "markers", "smoke: 标记冒烟测试"
    )
    config.addinivalue_line(
        "markers", "regression: 标记回归测试"
    )


@pytest.fixture(scope="session")
def test_session_info():
    """
    测试会话信息
    
    提供当前测试会话的基本信息
    """
    return {
        "session_id": f"session-{int(time.time())}",
        "start_time": datetime.now(),
        "test_environment": os.environ.get("TEST_ENV", "test"),
        "build_number": os.environ.get("BUILD_NUMBER", "local"),
        "git_commit": os.environ.get("GIT_COMMIT", "unknown")
    }


if __name__ == "__main__":
    print("Allure测试配置模块")
    print("提供全局的Allure配置和fixture支持")